package com.fjec.market.service.impl;

import com.aliyuncs.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fjec.common.Const;
import com.fjec.common.enums.EnumSysCode;
import com.fjec.common.exception.BizException;
import com.fjec.common.protocol.JsonResult;
import com.fjec.common.shiro.AccountInfo;
import com.fjec.common.util.DateUtil;
import com.fjec.market.entity.*;
import com.fjec.market.feign.ActivityClient;
import com.fjec.market.feign.UserClient;
import com.fjec.market.mapper.*;
import com.fjec.market.service.*;
import com.sun.org.apache.xpath.internal.axes.AttributeIterator;
import org.apache.commons.collections.MapUtils;
import org.elasticsearch.common.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional(rollbackFor = Throwable.class)
public class ShopServiceImpl implements IShopService {

    @Resource
    private InfoFarmerMapper infoFarmerMapper;

    @Resource
    private InfoBusinessMapper infoBusinessMapper;

    @Resource
    private InfoPurchaseMapper infoPurchaseMapper;

    @Resource
    private BizMarketBusiMapper bizMarketBusiMapper;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private UserClient userClient;

    @Resource
    private ActivityClient activityClient;

    @Resource
    private InfoSpuMapper spuMapper;

    @Resource
    private IInfoYsepayRegisterService infoYsepayRegisterService;

    @Resource
    private IInfoFarmerService infoFarmerService;

    @Resource
    private IInfoBusinessService infoBusinessService;

    @Resource
    private InfoPersonalMapper personalMapper;

    @Resource
    private IBizFollowService bizFollowService;

    @Resource
    private IBizFavoriteService bizFavoriteService;

    @Resource
    private IInfoSkuService infoSkuService;

    @Override
    public JsonResult getShopPhone() {
        Map<String, Object> resultMap = null;
        Integer busiType = AccountInfo.getBusiType();
        Long busiId = AccountInfo.getBusiId();
        switch (busiType) {
            case 2:
                resultMap = this.getFarmerPhone(busiId);
                break;
            case 3:
            case 4:
            case 5:
                resultMap = this.getBusinessPhone(busiId);
                break;
            case 6:
                resultMap = this.getPurchasePhone(busiId);
                break;
        }
        if (resultMap != null) {
            return JsonResult.success()
                    .data(resultMap)
                    .build();
        } else {
            return JsonResult.failure()
                    .code(EnumSysCode.ERR_0002.getCode())
                    .message(EnumSysCode.ERR_0002.getMsg())
                    .build();
        }
    }

    @Override
    public JsonResult updateShopPhone(String newPhone, String verifyCode) {
        // check new phone is null
        if (Strings.isNullOrEmpty(newPhone)) {
            return JsonResult.failure()
                    .code(EnumSysCode.ERR_0030.getCode())
                    .message(EnumSysCode.ERR_0030.getMsg())
                    .build();
        }
        // check verify code is null
        if (Strings.isNullOrEmpty(verifyCode)) {
            return JsonResult.failure()
                    .code(EnumSysCode.ERR_0030.getCode())
                    .message(EnumSysCode.ERR_0030.getMsg())
                    .build();
        }
        // check verify code
        String cachedVerifyCodeKey = Const.FJEC_SMS_VERIFY_CODE_KEY + newPhone;
        Object cachedVerifyCode = redisTemplate.opsForValue().get(cachedVerifyCodeKey);
        if (!Strings.isNullOrEmpty(verifyCode) && !Objects.equals(cachedVerifyCode, verifyCode)) {
            return JsonResult.failure()
                    .code(EnumSysCode.ERR_3009.getCode())
                    .message(EnumSysCode.ERR_3009.getMsg())
                    .build();
        }
        // update info
        Integer busiType = AccountInfo.getBusiType();
        Long busiId = AccountInfo.getBusiId();
        switch (busiType) {
            case 2:
                InfoFarmer farmer = new InfoFarmer();
                farmer.setId(busiId);
                farmer.setPhone(newPhone);
                farmer.setUpdateTime(DateUtil.nowLdt());
                infoFarmerMapper.updateById(farmer);
                break;
            case 3:
            case 4:
            case 5:
                InfoBusiness business = new InfoBusiness();
                business.setId(busiId);
                business.setPhone(newPhone);
                business.setUpdateTime(DateUtil.nowLdt());
                infoBusinessMapper.updateById(business);
                break;
            case 6:
                InfoPurchase purchase = new InfoPurchase();
                purchase.setId(busiId);
                purchase.setPhone(newPhone);
                purchase.setUpdateTime(DateUtil.nowLdt());
                infoPurchaseMapper.updateById(purchase);
                break;
        }
        // rpc update SysUser phone
        int result = userClient.updateUserPhone(AccountInfo.getUserId(), newPhone);
        if (result == 3014) {
            throw new BizException(EnumSysCode.ERR_3014.getCode(), EnumSysCode.ERR_3014.getMsg());
        }
        if (result != 1) {
            throw new BizException(EnumSysCode.ERR_3001.getCode(), EnumSysCode.ERR_3001.getMsg());
        }
        redisTemplate.delete(cachedVerifyCodeKey);
        return JsonResult.success()
                .code(EnumSysCode.MSG_6003.getCode())
                .message(EnumSysCode.MSG_6003.getMsg())
                .build();
    }

    @Override
    public JsonResult updateShopAllowPhone(Integer allowPhone) {
        Integer busiType = AccountInfo.getBusiType();
        Long busiId = AccountInfo.getBusiId();
        switch (busiType) {
            case 2:
                InfoFarmer farmer = new InfoFarmer();
                farmer.setId(busiId);
                farmer.setAllowPhone(allowPhone);
                farmer.setUpdateTime(DateUtil.nowLdt());
                infoFarmerMapper.updateById(farmer);
                break;
            case 3:
            case 4:
            case 5:
                InfoBusiness business = new InfoBusiness();
                business.setId(busiId);
                business.setAllowPhone(allowPhone);
                business.setUpdateTime(DateUtil.nowLdt());
                infoBusinessMapper.updateById(business);
                break;
            case 6:
                InfoPurchase purchase = new InfoPurchase();
                purchase.setId(busiId);
                purchase.setAllowPhone(allowPhone);
                purchase.setUpdateTime(DateUtil.nowLdt());
                infoPurchaseMapper.updateById(purchase);
                break;
        }
        return JsonResult.success()
                .code(EnumSysCode.MSG_6003.getCode())
                .message(EnumSysCode.MSG_6003.getMsg())
                .build();
    }

    @Override
    public boolean checkSuccessInfo() {
        Integer busiType = AccountInfo.getBusiType();
        Long busiId = AccountInfo.getBusiId();
        boolean isSuccessInfo = true;
        switch (busiType) {
            case 2:
                InfoFarmer farmer = infoFarmerMapper.selectById(busiId);
                isSuccessInfo = !Strings.isNullOrEmpty(farmer.getCompHeadPic());
                break;
            case 3:
            case 4:
            case 5:
                InfoBusiness business = infoBusinessMapper.selectById(busiId);
                isSuccessInfo = !Strings.isNullOrEmpty(business.getCompHeadPic());
                break;
            case 6:
                InfoPurchase purchase = infoPurchaseMapper.selectById(busiId);
                isSuccessInfo = !Strings.isNullOrEmpty(purchase.getCompHeadPic());
                break;
        }
        return isSuccessInfo;
    }

    @Override
    public JsonResult mainButtonDisplay() {
        Map<String, Object> resultMap = new HashMap<>();
        Integer busiType = AccountInfo.getBusiType();
        Long busiId = AccountInfo.getBusiId();
        Long userId = AccountInfo.getUserId();
        // 是否交保证金
        Integer deposit = 0;
        switch (busiType) {
            case 2:
                InfoFarmer farmer = infoFarmerMapper.selectById(busiId);
                if (farmer == null) {
                    return JsonResult.failure()
                            .code(EnumSysCode.ERR_3016.getCode())
                            .message(EnumSysCode.ERR_3016.getMsg())
                            .build();
                }
                deposit = farmer.getDepoStatus();
                break;
            case 3:
            case 4:
            case 5:
                InfoBusiness business = infoBusinessMapper.selectById(busiId);
                if (business == null) {
                    return JsonResult.failure()
                            .code(EnumSysCode.ERR_3016.getCode())
                            .message(EnumSysCode.ERR_3016.getMsg())
                            .build();
                }
                deposit = business.getDepoStatus();
                break;
            case 6:
                // 采购商没有订单管理
//                InfoPurchase purchase = infoPurchaseMapper.selectById(busiId);
                deposit = 0; // purchase.getDepoStatus() == 1;
                break;
        }
        resultMap.put("deposit", deposit == 1);
        // 未读消息
        Map<String, Object> tempMap = userClient.getUnReadNum(userId);
        resultMap.putAll(tempMap);
        // 商铺是否属于多个市场
        tempMap = bizMarketBusiMapper.getMarketCountForShop(busiType, busiId);
        resultMap.put("mcCount", MapUtils.getInteger(tempMap, "McCount"));
        resultMap.put("markCode", MapUtils.getInteger(tempMap, "MarkCode"));
        // 处理店铺未完善信息，不可以秒杀和送礼物
        tempMap = personalMapper.getShopRegStatusByUserId(userId);
        Integer shopRegStatus = MapUtils.getInteger(tempMap, "regStatus", 0);
        if (shopRegStatus < 2) {
            // 未完善信息的商户或个人不显示秒杀和送礼物
            resultMap.put("hasSeckillOrGiving", 0);
        } else {
            // 该用户是否存在可参与的秒杀活动或被赠送礼物 0=无 1=有秒杀 2=有赠送 3=both
            if (deposit == 2 || deposit == 3) {
                resultMap.put("hasSeckillOrGiving", 0);
            } else {
                Integer hasSeckillOrGiving = activityClient.hasSeckillOrGiving(AccountInfo.getUserId(),
                        AccountInfo.getBusiType(),
                        AccountInfo.getBusiId());
                resultMap.put("hasSeckillOrGiving", hasSeckillOrGiving);
            }
        }
        return JsonResult.success()
                .data(resultMap)
                .build();
    }

    @Override
    public List<Map<String, Object>> getFarmerShopStar() {
        return spuMapper.getShopStarByTypeForSchedule(Arrays.asList(new Integer[]{2}));
    }

    @Override
    public List<Map<String, Object>> getBusinessShopStar() {
        return spuMapper.getShopStarByTypeForSchedule(Arrays.asList(new Integer[]{3, 4, 5}));
    }

    @Override
    public List<Map<String, Object>> getPurchaseShopStar() {
        return spuMapper.getShopStarByTypeForSchedule(Arrays.asList(new Integer[]{6}));
    }

    private Map<String, Object> getFarmerPhone(Long busiId) {
        Map<String, Object> map = new HashMap<>();
        InfoFarmer farmer = infoFarmerMapper.selectById(busiId);
        if (farmer != null) {
            map.put("phone", farmer.getPhone());
            map.put("allowPhone", farmer.getAllowPhone() == 1 ? true : false);
            return map;
        } else {
            return null;
        }
    }

    private Map<String, Object> getBusinessPhone(Long busiId) {
        Map<String, Object> map = new HashMap<>();
        InfoBusiness business = infoBusinessMapper.selectById(busiId);
        if (business != null) {
            map.put("phone", business.getPhone());
            map.put("allowPhone", business.getAllowPhone() == 1 ? true : false);
            return map;
        } else {
            return null;
        }
    }

    private Map<String, Object> getPurchasePhone(Long busiId) {
        Map<String, Object> map = new HashMap<>();
        InfoPurchase purchase = infoPurchaseMapper.selectById(busiId);
        if (purchase != null) {
            map.put("phone", purchase.getPhone());
            map.put("allowPhone", purchase.getAllowPhone() == 1 ? true : false);
            return map;
        } else {
            return null;
        }
    }

    @Override
    public List<Map<String, Object>> getDepoInfoByConditions(Integer searchBy, String title, Integer busiType, Integer markCode, Integer depoStatus, Integer timedBy, String startTime, String endTime, Page page) {
        LocalDateTime sTime = null;
        LocalDateTime eTime = null;
        if (!StringUtils.isEmpty(startTime) && !StringUtils.isEmpty(endTime)) {
            sTime = LocalDateTime.of(DateUtil.parseLd(startTime, "yyyy-MM-dd"), LocalTime.MIN);
            eTime = LocalDateTime.of(DateUtil.parseLd(endTime, "yyyy-MM-dd"), LocalTime.MAX);
        }
        return infoFarmerMapper.getDepoInfoByConditions(searchBy, title, busiType, markCode,
                depoStatus, timedBy, sTime, eTime, page);
    }

    @Override
    public Long getTotalDepoByConditions(Integer searchBy, String title, Integer busiType, Integer markCode, Integer depoStatus, Integer timedBy, String startTime, String endTime) {
        return infoFarmerMapper.getTotalDepoByConditions(searchBy, title, busiType, markCode, depoStatus, timedBy, startTime, endTime);
    }

    @Override
    public Map<String, Object> getAll4Status() {
        Map<String, Object> result = new HashMap<>();
        boolean infoComplete = this.checkSuccessInfo();
        Map<String, Object> ysRegStatus = infoYsepayRegisterService.getYsRegStatus();
        Map<String, Object> depoStatus = infoBusinessService.getDepoStatus(AccountInfo.getUserId());
        result.put("infoComplete", infoComplete);
        result.put("regStatus", ysRegStatus);
        result.put("depoStatus", MapUtils.getInteger(depoStatus, "DepoStatus"));
        Integer bindWechatSuccess = 0;
        if (MapUtils.getInteger(ysRegStatus, "bindWechatSuccess") != null)
            bindWechatSuccess = MapUtils.getInteger(ysRegStatus, "bindWechatSuccess");
        result.put("bindWechatSuccess", bindWechatSuccess);
        return result;
    }

    @Override
    public Map<String, Object> getShopRegStatusByUserId(Long userId) {
        return personalMapper.getShopRegStatusByUserId(userId);
    }

    @Override
    public int refundDeposit(Long busiId, Integer busiType) {
        if (busiType == 2) {
            boolean c = infoFarmerService.update(new UpdateWrapper<InfoFarmer>()
                    .eq("Id", busiId)
                    .eq("DepoStatus", 2)
                    .set("DepoStatus", 3)
                    .set("DepoRefundTime", DateUtil.nowLdt()));
            if (c)
                return 1;
            else
                return -1;
        } else if (busiType == 3 || busiType == 4 || busiType == 5) {
            boolean c = infoBusinessService.update(new UpdateWrapper<InfoBusiness>()
                    .eq("Id", busiId)
                    .eq("DepoStatus", 2)
                    .set("DepoStatus", 3)
                    .set("DepoRefundTime", DateUtil.nowLdt()));
            if (c)
                return 1;
            else
                return -1;
        }
        return -1;
    }

    @Override
    public int applyRefundDeposit() {
        Long busiId = AccountInfo.getBusiId();
        // 删除关注关系
        bizFollowService.remove(new QueryWrapper<BizFollow>().eq("BusiId", busiId));
        // 删除收藏关系
        List<Long> skuIds = infoSkuService.list(new QueryWrapper<InfoSku>().eq("BusiId", busiId))
                .stream()
                .map(InfoSku::getId)
                .collect(Collectors.toList());
        if (skuIds.size() > 0) {
            bizFavoriteService.remove(new QueryWrapper<BizFavorite>().in("SkuId", skuIds));
        }

        Integer busiType = AccountInfo.getBusiType();
        if (busiType == 2) {
            boolean c = infoFarmerService.update(new UpdateWrapper<InfoFarmer>()
                    .eq("Id", busiId)
                    .eq("DepoStatus", 1)
                    .set("DepoStatus", 2)
                    .set("DepoApplyBackTime", DateUtil.nowLdt()));
            if (c)
                return 1;
            else
                return -1;
        } else if (busiType == 3 || busiType == 4 || busiType == 5) {
            boolean c = infoBusinessService.update(new UpdateWrapper<InfoBusiness>()
                    .eq("Id", busiId)
                    .eq("DepoStatus", 1)
                    .set("DepoStatus", 2)
                    .set("DepoApplyBackTime", DateUtil.nowLdt()));
            if (c)
                return 1;
            else
                return -1;
        }
        return -1;
    }

}
